#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import re
import logging
import weakref

from tree_sitter import Tree, Node
from datetime import datetime
from typing import Any, Dict, List, Optional, Union
from dataclasses import is_dataclass, fields

from parser.refactor.data_structures import ClassInfo
from parser.refactor.java_node_type import JavaNodeType

logger = logging.getLogger(__name__)


class JavaMetadataExtractor:
    """Java元数据提取器"""

    def __init__(self):
        # 初始化正则表达式模式
        self.package_pattern = re.compile(r'package\s+([\w.]+)\s*;')
        self.import_pattern = re.compile(r'import\s+(?:static\s+)?([\w.*]+)\s*;')
        self.class_pattern = re.compile(
            r'(?:public\s+|protected\s+|private\s+)?'  # 可见性修饰符
            r'(?:abstract\s+|final\s+|static\s+)*'  # 其他修饰符
            r'(?:class|interface|enum|@interface)\s+'  # 类型关键字
            r'(\w+)'  # 类名
        )


    @staticmethod
    def get_node_text(node: Node, code_bytes: bytes) -> str:
        """
        获取节点对应的源代码文本

        Args:
            node: 语法树节点
            code_bytes: 源代码的字节表示

        Returns:
            节点对应的文本
        """
        return code_bytes[node.start_byte:node.end_byte].decode('utf8')

    @staticmethod
    def to_dict(key: str, obj: Any) -> Dict[str, Any]:
        """
        将对象转换为字典表示

        Args:
            key: 主键
            obj: 要转换的对象(AnnotationInfo/ClassInfo/CommentInfo/FileInfo/MethodInfo)

        Returns:
            Dict[str, Any]: 字典表示
        """
        # 如果对象为None，返回None
        if obj is None:
            return dict(key=key, value=None)

        # 如果对象已经是字典，直接返回
        if isinstance(obj, dict):
            return obj

        # 如果是dataclass实例
        if is_dataclass(obj):
            return JavaMetadataExtractor._convert_dataclass(obj)

        # 如果是列表
        if isinstance(obj, list):
            return [JavaMetadataExtractor.to_dict(item) for item in obj]

        # 如果是集合
        if isinstance(obj, set):
            return {JavaMetadataExtractor.to_dict(item) for item in obj}

        # 如果是元组
        if isinstance(obj, tuple):
            return tuple(JavaMetadataExtractor.to_dict(item) for item in obj)

        # 如果是基本类型，直接返回
        if isinstance(obj, (str, int, float, bool)):
            return obj

        # 如果是datetime对象
        if isinstance(obj, datetime):
            return obj.isoformat()

        # 如果有自定义的to_dict方法
        if hasattr(obj, 'to_dict'):
            return obj.to_dict()

        # 尝试将对象的__dict__转换为字典
        if hasattr(obj, '__dict__'):
            return JavaMetadataExtractor._convert_object_dict(obj.__dict__)

        # 其他情况转换为字符串
        return str(obj)

    @staticmethod
    def _convert_dataclass(obj: Any) -> Dict[str, Any]:
        """转换dataclass实例"""
        result = {}
        for field in fields(obj):
            value = getattr(obj, field.name)
            result[field.name] = JavaMetadataExtractor.to_dict(value)
        return result

    @staticmethod
    def _convert_object_dict(obj_dict: Dict[str, Any]) -> Dict[str, Any]:
        """转换对象的__dict__"""
        result = {}
        for key, value in obj_dict.items():
            # 跳过私有属性
            if not key.startswith('_'):
                result[key] = JavaMetadataExtractor.to_dict(value)
        return result

    @staticmethod
    def extract_full_name_by_imports(simple_name: str, package_name: str,
                                     import_list: List[str], class_name_map: Dict[str, ClassInfo]) -> str:
        """
        根据Java代码中的导入语句, 获取所输入类的全限定名
        1. 查找直接导入
        2. 查找通配符导入
        3. 均未匹配时, 认为与当前类同一个包, 默认返回包名拼接

        Args:
            simple_name: 输入类的简单名
            package_name: 当前包名
            import_list: 当前import列表(已去除import、static、;)
            class_name_map: # 类名到类信息的映射

        Returns:
            所输入类的全限定名
        """

        # 1. 查找直接导入
        for import_text in import_list:
            if simple_name == import_text.split('.')[-1]:
                return import_text

        # 2. 查找通配符导入
        for import_text in import_list:
            if import_text.endswith('.*'):
                import_prefix = import_text[:-2]
                class_full_name = f"{import_prefix}.{simple_name}"
                if class_full_name in class_name_map:
                    return class_full_name

        # 3. 均未匹配时, 认为与当前类同一个包, 包名非空时返回包名拼接
        if package_name:
            return f"{package_name}.{simple_name}"

        # 4. 兜底返回简单名
        return simple_name


    @staticmethod
    def find_all_nodes(self, root, node_type):
        """查找特定类型的所有节点"""
        nodes = []

        def traverse(node):
            if node.type == node_type:
                nodes.append(node)
            for child in node.children:
                traverse(child)

        traverse(root)
        return nodes

    @staticmethod
    def _resolve_type_name(type_name: str, package_name: str,
                           imports_map: Dict[str, Any]) -> str:
        """
        解析类型的全限定名

        Args:
            type_name: 类型名称
            package_name: 当前包名
            imports_map: 导入映射

        Returns:
            str: 类型的全限定名
        """
        # 如果已经是全限定名，直接返回
        if '.' in type_name:
            return type_name

        # 检查是否在导入映射中
        if type_name in imports_map:
            return imports_map[type_name]

        # 如果是java.lang包中的类，添加包名
        if type_name in {'String', 'Object', 'Exception', 'RuntimeException',
                         'Throwable', 'Integer', 'Long', 'Boolean', 'Byte',
                         'Character', 'Float', 'Double', 'Void'}:
            return f"java.lang.{type_name}"

        # 假设是同包的类
        if package_name:
            return f"{package_name}.{type_name}"

        # 如果无法解析，返回原始名称
        return type_name


def main():
    """测试代码"""
    extractor = JavaMetadataExtractor()

    # 测试用的Java代码
    test_code = """
    package com.example.project;

    import java.util.List;
    import static java.util.Collections.*;

    /**
     * 这是一个测试类
     */
    public abstract class TestClass extends BaseClass implements Interface1, Interface2 {
        // 这是一个字段
        private String field;

        /*
         * 这是一个方法
         */
        public void method() {
            String text = "Hello";
            ArrayList<String> list = new ArrayList<>();
        }
    }
    """

    # 将测试代码写入临时文件
    with open('test.java', 'w', encoding='utf-8') as f:
        f.write(test_code)

    # 提取元数据
    metadata = extractor.extract_metadata('test.java')

    # 打印结果
    import json
    print(json.dumps(metadata, indent=2))

    # 清理临时文件
    os.remove('test.java')


if __name__ == '__main__':
    main()